#include<sys/select.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>


int main() {
  // 创建套接字并且进行异常预防处理；
  int lfd = socket(AF_INET,SOCK_STREAM,0);
  if (lfd<0) {
    perror("socket build failed!");
    exit(-1);
  }
  
  // 设置IO端口多路复用；
  int opt=1;
  int ret = setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
  if (ret<0) {
    perror("setsocket failed;");
    close(lfd);
    exit(-1);
  }
  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_port = htons(8888);
  inet_pton(AF_INET,"127.0.0.1",&addr.sin_addr);
  // 初始化网络地址结构体；
  ret = bind(lfd,(struct sockaddr*)&addr,sizeof(addr));
  if (ret<0) {
    perror("socket bind failed, please check your socket addr");
    close(lfd);
    exit(-1);
  } 
  ret = listen(lfd,256);
  if (ret<0) {
    perror("listen error;");
    close(lfd);
    exit(-1);
  }
  
  int maxfd =lfd;
  fd_set tmpfds,cfds;
  FD_ZERO(&tmpfds);
  FD_ZERO(&cfds);
  FD_SET(lfd,&cfds);
  int nready;
  int len = sizeof(struct sockaddr_in);
  while(1){
    tmpfds = cfds;
    nready = select(maxfd+1,&tmpfds,NULL,NULL,NULL);
    if (nready>0)
    {
      /* code */
      if(FD_ISSET(lfd,&tmpfds)) {
      // 发现新连接请求到来；
      struct sockaddr_in clientaddr;
      int cfd = accept(lfd,(struct sockaddr*)&clientaddr,&len);
      if(cfd<0) {
        if(errno==EINTR||errno==ECONNABORTED){
          continue;
          // 如果是因为中断或者连接被弃用导致中断就跳出当前循环；
        }
        break; // 此外的异常情况需要进行退出
      }
      // char ipbuf[32];
      // inet_ntop(AF_INET,&clientaddr.sin_addr,ipbuf,32);
      // printf("连接ip地址为%s,端口为%d",ipbuf,ntohs(clientaddr.sin_port));
      FD_SET(cfd,&cfds);
      maxfd = cfd>maxfd? cfd : maxfd;

    }
    for ( int i = lfd+1; i<=maxfd; ++i) {
      if ( FD_ISSET(i,&cfds)) {
        char buf[1024];
        memset(buf,0x00,sizeof(buf));
        int ret = read(i,buf,sizeof(buf));
        if(ret){
          printf("client sendmsg: %s\n",buf);

        }else if(ret==0) {
          printf("client connect close\n");
          FD_CLR(i,&cfds);
          close(i);
        }else{
          perror(" read failed ");
          close(i);
          FD_CLR(i,&cfds);

        }
        if(--nready<=0)
        break;

      }

    }
    }
    
      // 如果监听的文件描述符有事件响应；


  }
    close(lfd);

  

return 0;

}